Įvaldykite SQLAlchemy hibridines savybes, kad sukurtumėte apskaičiuojamus atributus, skirtus išraiškingesniems ir lengviau prižiūrimiems duomenų modeliams. Mokykitės su praktiniais pavyzdžiais.
Python SQLAlchemy Hibridinės Savybės: Apskaičiuojami Atributai Galingam Duomenų Modeliavimui
SQLAlchemy, galingas ir lankstus Python SQL įrankių rinkinys ir objektų-reliacijų atvaizdavimo priemonė (ORM), siūlo platų funkcijų rinkinį darbui su duomenų bazėmis. Tarp jų, Hibridinės Savybės išsiskiria kaip ypač naudingas įrankis apskaičiuojamiems atributams kurti jūsų duomenų modeliuose. Šis straipsnis pateikia išsamų vadovą, kaip suprasti ir naudoti SQLAlchemy hibridines savybes, leidžiantį jums kurti išraiškingesnes, lengviau prižiūrimas ir efektyvesnes programas.
Kas yra SQLAlchemy Hibridinės Savybės?
Hibridinė Savybė, kaip rodo pavadinimas, yra ypatingas savybės tipas SQLAlchemy, kuris gali elgtis skirtingai, priklausomai nuo konteksto, kuriame jis pasiekiamas. Ji leidžia apibrėžti atributą, kuris gali būti pasiekiamas tiesiogiai klasės egzemplioriuje (kaip įprasta savybė) arba naudojamas SQL išraiškose (kaip stulpelis). Tai pasiekiama apibrėžiant atskiras funkcijas tiek egzemplioriaus, tiek klasės lygiu.
Iš esmės, Hibridinės Savybės suteikia būdą apibrėžti apskaičiuojamus atributus, kurie yra gaunami iš kitų jūsų modelio atributų. Šie apskaičiuojami atributai gali būti naudojami užklausose, taip pat jie gali būti pasiekiami tiesiogiai jūsų modelio egzemplioriuose, suteikiant nuoseklią ir intuityvią sąsają.
Kodėl Verta Naudoti Hibridines Savybes?
Hibridinių Savybių naudojimas siūlo keletą privalumų:
- Išraiškingumas: Jos leidžia jums išreikšti sudėtingus ryšius ir skaičiavimus tiesiogiai jūsų modelyje, todėl jūsų kodas tampa skaitomesnis ir lengviau suprantamas.
- Priežiūra: Apgaubiant sudėtingą logiką Hibridinėse Savybėse, sumažinate kodo dubliavimą ir pagerinate savo programos priežiūrą.
- Efektyvumas: Hibridinės Savybės leidžia jums atlikti skaičiavimus tiesiogiai duomenų bazėje, sumažindamos duomenų kiekį, kurį reikia perkelti tarp jūsų programos ir duomenų bazės serverio.
- Nuoseklumas: Jos suteikia nuoseklią sąsają apskaičiuojamiems atributams pasiekti, nepriklausomai nuo to, ar dirbate su savo modelio egzemplioriais, ar rašote SQL užklausas.
Pagrindinis Pavyzdys: Pilnas Vardas
Pradėkime nuo paprasto pavyzdžio: asmens pilno vardo apskaičiavimo iš jo vardo ir pavardės.
Modelio Apibrėžimas
Pirma, apibrėžiame paprastą `Person` modelį su `first_name` ir `last_name` stulpeliais.
from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.hybrid import hybrid_property
Base = declarative_base()
class Person(Base):
__tablename__ = 'people'
id = Column(Integer, primary_key=True)
first_name = Column(String)
last_name = Column(String)
def __repr__(self):
return f""
engine = create_engine('sqlite:///:memory:') # Atminties duomenų bazė pavyzdžiui
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
session = Session()
Hibridinės Savybės Kūrimas
Dabar pridėsime `full_name` Hibridinę Savybę, kuri sujungia vardą ir pavardę.
class Person(Base):
__tablename__ = 'people'
id = Column(Integer, primary_key=True)
first_name = Column(String)
last_name = Column(String)
@hybrid_property
def full_name(self):
return f"{self.first_name} {self.last_name}"
def __repr__(self):
return f""
Šiame pavyzdyje `@hybrid_property` dekoratorius paverčia `full_name` metodą į Hibridinę Savybę. Kai pasieksite `person.full_name`, kodas, esantis šiame metode, bus vykdomas.
Hibridinės Savybės Pasiekimas
Sukurkime šiek tiek duomenų ir pažiūrėkime, kaip pasiekti `full_name` savybę.
person1 = Person(first_name='Alice', last_name='Smith')
person2 = Person(first_name='Bob', last_name='Johnson')
session.add_all([person1, person2])
session.commit()
print(person1.full_name) # Išvestis: Alice Smith
print(person2.full_name) # Išvestis: Bob Johnson
Hibridinės Savybės Naudojimas Užklausose
Tikroji Hibridinių Savybių galia atsiskleidžia, kai jas naudojate užklausose. Mes galime filtruoti pagal `full_name`, tarsi tai būtų įprastas stulpelis.
people_with_smith = session.query(Person).filter(Person.full_name == 'Alice Smith').all()
print(people_with_smith) # Išvestis: []
Tačiau aukščiau pateiktas pavyzdys veiks tik paprastiems lygybės patikrinimams. Norėdami atlikti sudėtingesnes operacijas užklausose (pvz., `LIKE`), turime apibrėžti išraiškos funkciją.
Išraiškos Funkcijų Apibrėžimas
Norėdami naudoti Hibridines Savybes sudėtingesnėse SQL išraiškose, turite apibrėžti išraiškos funkciją. Ši funkcija pasako SQLAlchemy, kaip išversti Hibridinę Savybę į SQL išraišką.
Pakeiskime ankstesnį pavyzdį, kad palaikytume `LIKE` užklausas `full_name` savybėje.
from sqlalchemy import func
class Person(Base):
__tablename__ = 'people'
id = Column(Integer, primary_key=True)
first_name = Column(String)
last_name = Column(String)
@hybrid_property
def full_name(self):
return f"{self.first_name} {self.last_name}"
@full_name.expression
def full_name(cls):
return func.concat(cls.first_name, ' ', cls.last_name)
def __repr__(self):
return f""
Čia pridėjome `@full_name.expression` dekoratorių. Tai apibrėžia funkciją, kuri priima klasę (`cls`) kaip argumentą ir grąžina SQL išraišką, kuri sujungia vardą ir pavardę naudodama `func.concat` funkciją. `func.concat` yra SQLAlchemy funkcija, kuri atspindi duomenų bazės sujungimo funkciją (pvz., `||` SQLite, `CONCAT` MySQL ir PostgreSQL).
Dabar galime naudoti `LIKE` užklausas:
people_with_smith = session.query(Person).filter(Person.full_name.like('%Smith%')).all()
print(people_with_smith) # Išvestis: []
Reikšmių Nustatymas: Nustatymo Funkcija
Hibridinės Savybės taip pat gali turėti nustatymo funkcijas, leidžiančias atnaujinti pagrindinius atributus pagal naują reikšmę. Tai daroma naudojant `@full_name.setter` dekoratorių.
Pridėkime nustatymo funkciją prie mūsų `full_name` savybės, kuri padalija pilną vardą į vardą ir pavardę.
class Person(Base):
__tablename__ = 'people'
id = Column(Integer, primary_key=True)
first_name = Column(String)
last_name = Column(String)
@hybrid_property
def full_name(self):
return f"{self.first_name} {self.last_name}"
@full_name.expression
def full_name(cls):
return func.concat(cls.first_name, ' ', cls.last_name)
@full_name.setter
def full_name(self, full_name):
parts = full_name.split()
self.first_name = parts[0]
self.last_name = ' '.join(parts[1:]) if len(parts) > 1 else ''
def __repr__(self):
return f""
Dabar galite nustatyti `full_name` savybę, ir ji atnaujins `first_name` ir `last_name` atributus.
person = Person(first_name='Alice', last_name='Smith')
session.add(person)
session.commit()
person.full_name = 'Charlie Brown'
print(person.first_name) # Išvestis: Charlie
print(person.last_name) # Išvestis: Brown
session.commit()
Naikinimo Funkcijos
Panašiai kaip nustatymo funkcijos, taip pat galite apibrėžti naikinimo funkciją Hibridinei Savybei naudodami `@full_name.deleter` dekoratorių. Tai leidžia jums apibrėžti, kas nutinka, kai bandote `del person.full_name`.
Mūsų pavyzdžiui, panaikinkime pilną vardą, kad išvalytume tiek vardą, tiek pavardę.
class Person(Base):
__tablename__ = 'people'
id = Column(Integer, primary_key=True)
first_name = Column(String)
last_name = Column(String)
@hybrid_property
def full_name(self):
return f"{self.first_name} {self.last_name}"
@full_name.expression
def full_name(cls):
return func.concat(cls.first_name, ' ', cls.last_name)
@full_name.setter
def full_name(self, full_name):
parts = full_name.split()
self.first_name = parts[0]
self.last_name = ' '.join(parts[1:]) if len(parts) > 1 else ''
@full_name.deleter
def full_name(self):
self.first_name = None
self.last_name = None
def __repr__(self):
return f""
person = Person(first_name='Charlie', last_name='Brown')
session.add(person)
session.commit()
del person.full_name
print(person.first_name) # Išvestis: None
print(person.last_name) # Išvestis: None
session.commit()
Išplėstinis Pavyzdys: Amžiaus Apskaičiavimas pagal Gimimo Datą
Apsvarstykime sudėtingesnį pavyzdį: asmens amžiaus apskaičiavimą pagal jo gimimo datą. Tai parodo Hibridinių Savybių galią tvarkant datas ir atliekant skaičiavimus.
Gimimo Datos Stulpelio Pridėjimas
Pirma, pridėsime `date_of_birth` stulpelį prie mūsų `Person` modelio.
from sqlalchemy import Date
import datetime
class Person(Base):
__tablename__ = 'people'
id = Column(Integer, primary_key=True)
first_name = Column(String)
last_name = Column(String)
date_of_birth = Column(Date)
# ... (ankstesnis kodas)
Amžiaus Apskaičiavimas su Hibridine Savybe
Dabar sukuriame `age` Hibridinę Savybę. Ši savybė apskaičiuoja amžių pagal `date_of_birth` stulpelį. Turėsime atsižvelgti į atvejį, kai `date_of_birth` yra `None`.
from sqlalchemy import Date
import datetime
class Person(Base):
__tablename__ = 'people'
id = Column(Integer, primary_key=True)
first_name = Column(String)
last_name = Column(String)
date_of_birth = Column(Date)
@hybrid_property
def age(self):
if self.date_of_birth:
today = datetime.date.today()
age = today.year - self.date_of_birth.year - ((today.month, today.day) < (self.date_of_birth.month, self.date_of_birth.day))
return age
return None # Arba kita numatytoji reikšmė
@age.expression
def age(cls):
today = datetime.date.today()
return func.cast(func.strftime('%Y', 'now') - func.strftime('%Y', cls.date_of_birth) - (func.strftime('%m-%d', 'now') < func.strftime('%m-%d', cls.date_of_birth)), Integer)
# ... (ankstesnis kodas)
Svarbūs Aspektai:
- Duomenų Bazei Būdingos Datos Funkcijos: Išraiškos funkcija naudoja `func.strftime` datos skaičiavimams. Ši funkcija yra specifinė SQLite. Kitoms duomenų bazėms (pvz., PostgreSQL arba MySQL), turėsite naudoti atitinkamas duomenų bazei būdingas datos funkcijas (pvz., `EXTRACT` PostgreSQL, `YEAR` ir `MAKEDATE` MySQL).
- Tipų Konvertavimas: Mes naudojame `func.cast`, kad konvertuotume datos skaičiavimo rezultatą į sveikąjį skaičių. Tai užtikrina, kad `age` savybė grąžintų sveikojo skaičiaus reikšmę.
- Laiko Juostos: Būkite atidūs laiko juostoms dirbdami su datomis. Užtikrinkite, kad jūsų datos būtų saugomos ir lyginamos nuoseklioje laiko juostoje.
- `None` reikšmių tvarkymas Savybė turėtų apdoroti atvejus, kai `date_of_birth` yra `None`, kad būtų išvengta klaidų.
Amžiaus Savybės Naudojimas
person1 = Person(first_name='Alice', last_name='Smith', date_of_birth=datetime.date(1990, 1, 1))
person2 = Person(first_name='Bob', last_name='Johnson', date_of_birth=datetime.date(1985, 5, 10))
session.add_all([person1, person2])
session.commit()
print(person1.age) # Išvestis: (Priklauso nuo dabartinės datos ir gimimo datos)
print(person2.age) # Išvestis: (Priklauso nuo dabartinės datos ir gimimo datos)
people_over_30 = session.query(Person).filter(Person.age > 30).all()
print(people_over_30) # Išvestis: (Žmonės, vyresni nei 30 metų pagal dabartinę datą)
Sudėtingesni Pavyzdžiai ir Naudojimo Atvejai
Užsakymų Sumų Apskaičiavimas El. Komercijos Programoje
El. komercijos programoje galite turėti `Order` modelį su ryšiu su `OrderItem` modeliais. Galite naudoti Hibridinę Savybę, kad apskaičiuotumėte bendrą užsakymo vertę.
from sqlalchemy import ForeignKey, Float
from sqlalchemy.orm import relationship
class Order(Base):
__tablename__ = 'orders'
id = Column(Integer, primary_key=True)
items = relationship("OrderItem", back_populates="order")
@hybrid_property
def total(self):
return sum(item.price * item.quantity for item in self.items)
@total.expression
def total(cls):
return session.query(func.sum(OrderItem.price * OrderItem.quantity)).\
filter(OrderItem.order_id == cls.id).scalar_subquery()
class OrderItem(Base):
__tablename__ = 'order_items'
id = Column(Integer, primary_key=True)
order_id = Column(Integer, ForeignKey('orders.id'))
order = relationship("Order", back_populates="items")
price = Column(Float)
quantity = Column(Integer)
Šis pavyzdys demonstruoja sudėtingesnę išraiškos funkciją, naudojant subužklausą, kad apskaičiuotų sumą tiesiogiai duomenų bazėje.
Geografiniai Skaičiavimai
Jei dirbate su geografiniais duomenimis, galite naudoti Hibridines Savybes, kad apskaičiuotumėte atstumus tarp taškų arba nustatytumėte, ar taškas yra tam tikrame regione. Tai dažnai apima duomenų bazei būdingų geografinių funkcijų naudojimą (pvz., PostGIS funkcijos PostgreSQL).
from geoalchemy2 import Geometry
from sqlalchemy import cast
class Location(Base):
__tablename__ = 'locations'
id = Column(Integer, primary_key=True)
name = Column(String)
coordinates = Column(Geometry(geometry_type='POINT', srid=4326))
@hybrid_property
def latitude(self):
if self.coordinates:
return self.coordinates.x
return None
@latitude.expression
def latitude(cls):
return cast(func.ST_X(cls.coordinates), Float)
@hybrid_property
def longitude(self):
if self.coordinates:
return self.coordinates.y
return None
@longitude.expression
def longitude(cls):
return cast(func.ST_Y(cls.coordinates), Float)
Šiam pavyzdžiui reikia `geoalchemy2` plėtinio ir daroma prielaida, kad naudojate duomenų bazę su įjungtu PostGIS.
Geriausios Hibridinių Savybių Naudojimo Praktikos
- Laikykite Paprasta: Naudokite Hibridines Savybes palyginti paprastiems skaičiavimams. Sudėtingesnei logikai apsvarstykite galimybę naudoti atskiras funkcijas ar metodus.
- Naudokite Tinkamus Duomenų Tipus: Užtikrinkite, kad Hibridinėse Savybėse naudojami duomenų tipai būtų suderinami tiek su Python, tiek su SQL.
- Apsvarstykite Veikimą: Nors Hibridinės Savybės gali pagerinti našumą, atliekant skaičiavimus duomenų bazėje, būtina stebėti užklausų našumą ir optimizuoti jas, jei reikia.
- Kruopščiai Išbandykite: Kruopščiai išbandykite savo Hibridines Savybes, kad įsitikintumėte, jog jos pateikia teisingus rezultatus visuose kontekstuose.
- Dokumentuokite Savo Kodą: Aiškiai dokumentuokite savo Hibridines Savybes, kad paaiškintumėte, ką jos daro ir kaip veikia.
Dažni Sunkumai ir Kaip Jų Išvengti
- Duomenų Bazei Būdingos Funkcijos: Užtikrinkite, kad jūsų išraiškos funkcijos naudotų nuo duomenų bazės nepriklausomas funkcijas arba pateiktų duomenų bazei būdingus įgyvendinimus, kad išvengtumėte suderinamumo problemų.
- Neteisingos Išraiškos Funkcijos: Dar kartą patikrinkite, ar jūsų išraiškos funkcijos teisingai išverčia jūsų Hibridinę Savybę į galiojančią SQL išraišką.
- Našumo Siaurėjimo Vietos: Venkite naudoti Hibridines Savybes skaičiavimams, kurie yra per sudėtingi ar reikalaujantys daug išteklių, nes tai gali sukelti našumo siaurėjimo vietas.
- Konfliktiniai Pavadinimai: Venkite naudoti tą patį pavadinimą savo Hibridinei Savybei ir stulpeliui savo modelyje, nes tai gali sukelti painiavą ir klaidų.
Atsižvelgimas į Internacionalizavimą
Dirbdami su Hibridinėmis Savybėmis internacionalizuotose programose, atsižvelkite į šiuos dalykus:
- Datos ir Laiko Formatai: Naudokite atitinkamus datos ir laiko formatus skirtingoms lokalėms.
- Skaičių Formatai: Naudokite atitinkamus skaičių formatus skirtingoms lokalėms, įskaitant dešimtainius skyriklius ir tūkstančių skyriklius.
- Valiutos Formatai: Naudokite atitinkamus valiutos formatus skirtingoms lokalėms, įskaitant valiutos simbolius ir dešimtaines vietas.
- Eilučių Palyginimai: Naudokite nuo lokalės priklausančias eilučių palyginimo funkcijas, kad užtikrintumėte, jog eilutės būtų teisingai lyginamos skirtingomis kalbomis.
Pavyzdžiui, apskaičiuodami amžių, atsižvelkite į skirtingus datos formatus, naudojamus visame pasaulyje. Kai kuriuose regionuose data rašoma kaip `MM/DD/YYYY`, o kituose - `DD/MM/YYYY` arba `YYYY-MM-DD`. Įsitikinkite, kad jūsų kodas teisingai analizuoja datas visais formatais.
Sujungiant eilutes (kaip pavyzdyje su `full_name`), atkreipkite dėmesį į kultūrinius skirtumus vardų tvarkoje. Kai kuriose kultūrose pavardė eina prieš vardą. Apsvarstykite galimybę suteikti vartotojams galimybes pritaikyti vardo rodymo formatą.
Išvada
SQLAlchemy Hibridinės Savybės yra galingas įrankis apskaičiuojamiems atributams kurti jūsų duomenų modeliuose. Jos leidžia jums išreikšti sudėtingus ryšius ir skaičiavimus tiesiogiai jūsų modeliuose, pagerinant kodo skaitomumą, priežiūrą ir efektyvumą. Suprasdami, kaip apibrėžti Hibridines Savybes, išraiškos funkcijas, nustatymo funkcijas ir naikinimo funkcijas, galite pasinaudoti šia funkcija, kad sukurtumėte sudėtingesnes ir patikimesnes programas.
Laikydamiesi šiame straipsnyje pateiktų geriausių praktikų ir vengdami dažnų spąstų, galite efektyviai naudoti Hibridines Savybes, kad patobulintumėte savo SQLAlchemy modelius ir supaprastintumėte prieigos prie duomenų logiką. Nepamirškite atsižvelgti į internacionalizavimo aspektus, kad užtikrintumėte, jog jūsų programa veiktų teisingai vartotojams visame pasaulyje. Kruopščiai planuojant ir įgyvendinant, Hibridinės Savybės gali tapti neįkainojama jūsų SQLAlchemy įrankių rinkinio dalimi.